//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;

namespace Microsoft.Research.DataLayer
{

    public partial class AssemblyImage
    {

        /// <summary>
        /// Check if the assembly image is the latest version.
        /// </summary>
        /// <param name="assemblyImage">The assembly image.</param>
        /// <param name="connection">The registry connection.</param>
        /// <returns>True if the assembly image is the latest version. False otherwise.</returns>
        public bool IsLatestVersion()
        {
            bool result = false;
            this.NewerVersions.GetEnumerator();
            if (this.NewerVersions.Count == 0)
            {
                result = true;
            }
            return result;
        }

        /// <summary>
        /// Gets the oldest version.
        /// </summary>
        /// <param name="asmImg">The asm img.</param>
        /// <returns></returns>
        public static AssemblyImage GetOldestVersion(AssemblyImage asmImg)
        {
            AssemblyImage oldestVersion = null;
            asmImg.OlderVersions.GetEnumerator();
            if (asmImg.OlderVersions.Count > 0)
            {
                oldestVersion = GetOldestVersion(asmImg.OlderVersions[0].AssemblyImage_1);
                if (!oldestVersion.IsDeleted)
                {
                    oldestVersion = asmImg;
                }
            }
            else
            {
                oldestVersion = asmImg;
            }

            return oldestVersion;
        }


        /// <summary>
        /// Get all the older versions of the AssemblyImages. Stop when V-0 is reached.
        /// </summary>
        /// <param name="workflow">The workflow.</param>
        /// <param name="versionCollection">Collection of the versions of the workflow.</param>
        private void GetPreviousVersion(List<AssemblyImage> versionCollection)
        {
            #region Validation of Arguments

            if (null == versionCollection)
            {
                throw new ArgumentNullException("versionCollection");
            }

            #endregion

            this.OlderVersions.GetEnumerator();
            if (this.OlderVersions.Count > 0)
            {
                AssemblyImage oldVersion = this.OlderVersions[0].AssemblyImage_1;
                // Add the older version to the list if not labelled.
                if (!oldVersion.IsDeleted)
                {
                    versionCollection.Add(oldVersion);
                }

                oldVersion.GetPreviousVersion(versionCollection);
            }
        }

        public static List<AssemblyImage> GetPreviousVersions(AssemblyImage asmImg)
        {
            #region Validation of Arguments

            if (null == asmImg)
            {
                throw new ArgumentNullException("asmImg");
            }

            #endregion

            List<AssemblyImage> versions = new List<AssemblyImage>();
            asmImg.GetPreviousVersion(versions);

            // Sort the list based on the versions.
            versions.Sort(new AssemblyImageVersionComparer());
            return versions;
        }

        # region CommonSearches
        public sealed class CommonSearches
        {

            private CommonSearches()
            {
            }

            /// <summary>
            /// Get the assembly images which have the required extension.
            /// </summary>
            /// <param name="extension">The extension to search.</param>
            /// <param name="connection">The registry connection.</param>
            /// <returns>Collection of assembly images.</returns>
            public static Collection<AssemblyImage> GetAssemblyImagesByExtension(string extension, Connection connection)
            {
                #region Validation of Arguments
                if (string.IsNullOrEmpty(extension))
                {
                    throw new ArgumentNullException("extension");
                }
                if (null == connection)
                {
                    throw new ArgumentNullException("connection");
                }
                #endregion
                Collection<AssemblyImage> searchResults = null;

                try
                {
                    AssemblyImage.ISearch searchQuery = AssemblyImage.ISearch.Create();
                    searchQuery.Query = AssemblyImage.ISearch.AND(AssemblyImage.ISearch.FileExtension(StringField.Condition.Equals, extension),
                        AssemblyImage.ISearch.IsDeleted(BooleanField.Condition.Equals, false));
                    searchResults = new Collection<AssemblyImage>(AssemblyImage.Search(searchQuery, connection));
                }
                catch (RecordNotFoundException)
                {

                }
                return searchResults;
            }

            /// <summary>
            /// Search the assembly images by the specified name.
            /// </summary>
            /// <param name="imageName">The name of the assembly image.</param>
            /// <param name="connection">The registry connection.</param>
            /// <returns>The collection of assembly images which match the name.</returns>
            public static Collection<AssemblyImage> GetAssemblyImagesByName(string imageName, Connection connection)
            {
                #region Validation of Arguments
                if (string.IsNullOrEmpty(imageName))
                {
                    throw new ArgumentNullException("imageName");
                }
                if (null == connection)
                {
                    throw new ArgumentNullException("connection");
                }
                #endregion

                Collection<AssemblyImage> searchResults = null;

                try
                {
                    AssemblyImage.ISearch searchQuery = AssemblyImage.ISearch.Create();
                    searchQuery.Query = AssemblyImage.ISearch.AND(AssemblyImage.ISearch.Name(StringField.Condition.Equals, imageName),
                        AssemblyImage.ISearch.IsDeleted(BooleanField.Condition.Equals, false));
                    searchResults = new Collection<AssemblyImage>(AssemblyImage.Search(searchQuery, connection));
                }
                catch (RecordNotFoundException)
                {

                }
                return searchResults;
            }

            /// <summary>
            /// Search the assembly by the specified checksum.
            /// </summary>
            /// <param name="checksum">The checksum.</param>
            /// <param name="connection">Registry connection.</param>
            /// <returns>The collection of images with the matching checksum.</returns>
            public static Collection<AssemblyImage> GetAssemblyImagesByChecksum(string checksum, Connection connection)
            {
                #region Validation of Arguments
                if (string.IsNullOrEmpty(checksum))
                {
                    throw new ArgumentNullException("checksum");
                }
                if (null == connection)
                {
                    throw new ArgumentNullException("connection");
                }
                #endregion

                Collection<AssemblyImage> searchResults = null;

                try
                {
                    AssemblyImage.ISearch searchQuery = AssemblyImage.ISearch.Create();
                    searchQuery.Query = AssemblyImage.ISearch.AND(AssemblyImage.ISearch.Checksum(StringField.Condition.Equals, checksum),
                        AssemblyImage.ISearch.IsDeleted(BooleanField.Condition.Equals, false));
                    searchResults = new Collection<AssemblyImage>(AssemblyImage.Search(searchQuery, connection));
                }
                catch (RecordNotFoundException)
                {

                }
                return searchResults;
            }
        }
        #endregion

        /// <summary>
        /// Deletes the unused assemblyImage.
        /// </summary>
        public void DeleteUnused()
        {
            AssemblyImage oldVersion = null;
            this.OlderVersions.GetEnumerator();
            if (this.OlderVersions.Count > 0)
            {
                oldVersion = this.OlderVersions[0].AssemblyImage_1;
                this.OlderVersions.Clear();
            }

            AssemblyImage newVersion = null;
            this.NewerVersions.GetEnumerator();
            if (this.NewerVersions.Count > 0)
            {
                newVersion = this.NewerVersions[0].AssemblyImage_2;
                this.NewerVersions.Clear();
            }

            // Delete the contents of the assembly.
            this.Contents = null;

            Save();

            // Map the older and newer versions.
            if (oldVersion != null && newVersion != null)
            {
                oldVersion.NewerVersions.Clear();

                newVersion.OlderVersions.Clear();
                newVersion.SafeParentVersion = oldVersion;
                newVersion.Save();

                AssemblyImageVersion newerVersionInfo = AssemblyImageVersion.Create(oldVersion, newVersion, VersionRelationshipType.Concrete, Conn);
                oldVersion.NewerVersions.Add(newerVersionInfo);
            }

            if (newVersion != null && oldVersion == null)
            {
                newVersion.OlderVersions.Clear();
                newVersion.SafeParentVersion = null;

                newVersion.Save();
            }

            if (newVersion == null && oldVersion != null)
            {
                oldVersion.NewerVersions.Clear();
            }

            // Delete the assembly itself.
            Delete();
        }
    }


    /// <summary>
    /// The comparer for an AssemblyImage.
    /// </summary>
    public class AssemblyImageComparer : IEqualityComparer<AssemblyImage>
    {
        #region IEqualityComparer<AssemblyImage> Members

        /// <summary>
        /// Determines whether the specified objects are equal.
        /// </summary>
        /// <param name="x">The first object of type <paramref name="T"/> to compare.</param>
        /// <param name="y">The second object of type <paramref name="T"/> to compare.</param>
        /// <returns>
        /// true if the specified objects are equal; otherwise, false.
        /// </returns>
        public bool Equals(Microsoft.Research.DataLayer.AssemblyImage x, Microsoft.Research.DataLayer.AssemblyImage y)
        {
            return (x as IObject).ID.Equals((y as IObject).ID);
        }

        /// <summary>
        /// Returns a hash code for the specified object.
        /// </summary>
        /// <param name="obj">The <see cref="T:System.Object"/> for which a hash code is to be returned.</param>
        /// <returns>A hash code for the specified object.</returns>
        /// <exception cref="T:System.ArgumentNullException">The type of <paramref name="obj"/> is a reference type and <paramref name="obj"/> is null.</exception>
        public int GetHashCode(Microsoft.Research.DataLayer.AssemblyImage obj)
        {
            return (obj as IObject).ID.GetHashCode();
        }

        #endregion
    }

    /// <summary>
    /// The comparer for an activity sequence.
    /// </summary>
    public class AssemblyImageVersionComparer : IComparer<AssemblyImage>
    {

        #region IComparer<AssemblyImage> Members

        public int Compare(AssemblyImage x, AssemblyImage y)
        {
            return x.Version.CompareTo(y.Version);
        }

        #endregion
    }
}
